use std::any::Any;
use std::collections::HashMap;
use std::sync::Arc;
use bytes::{BytesMut};
use linked_hash_map::LinkedHashMap;
use crate::codec::{RpcEncode};
use crate::{decode, encode, RpcContext, RpcFilter, RpcResult};

#[derive(Clone)]
pub struct RpcRouter {
    routers: Arc<HashMap<&'static str, Box<dyn RouterFactory + 'static>>>,
    filters: Arc<LinkedHashMap<&'static str, Box<dyn RpcFilter + 'static>>>,
}

impl RpcRouter {
    pub fn new(routers: HashMap<&'static str, Box<dyn RouterFactory + 'static>>,
               filters: LinkedHashMap<&'static str, Box<dyn RpcFilter + 'static>>) -> Self {
        RpcRouter {
            routers: Arc::new(routers),
            filters: Arc::new(filters),
        }
    }

    pub fn get_router(&self, path: &str) ->  Option<&Box<dyn RouterFactory + 'static>> {
        self.routers.get(path)
    }

    pub fn get_filters(&self) -> Arc<LinkedHashMap<&'static str, Box<dyn RpcFilter + 'static>>> {
        self.filters.clone()
    }
}

pub trait DoRouter: Send + Any {
    fn execute(&mut self, rpc_context: &mut RpcContext) -> RpcResult<Box<dyn RpcEncode>>;
}

pub trait RouterFactory: Send + Sync {
    fn parse(&self, rpc_context: &RpcContext, bytes_mut: BytesMut) -> RpcResult<Box<dyn DoRouter>>;
}

pub trait RouterExecutor: Send + Sync {
    fn execute(&self, data: Vec<u8>, rpc_context: &RpcContext)-> RpcResult<Vec<u8>>;
}


/// p: 参数
/// R： 返回值
pub trait RouterBusinessExecutor<P, R> {

    fn execute(&self, p: P) -> RpcResult<R>;
}

pub struct DemoRouterBusinessExecutor;

impl RouterBusinessExecutor<i32, i32> for DemoRouterBusinessExecutor {
    fn execute(&self, _p: i32) -> RpcResult<i32> {
        todo!()
    }
}

pub struct DemoRouterExecutor {
    executor: DemoRouterBusinessExecutor,
}

impl RouterExecutor for DemoRouterExecutor {
    fn execute(&self, data: Vec<u8>, rpc_context: &RpcContext)-> RpcResult<Vec<u8>> {
        let p = decode::<i32>(rpc_context, data)?;
        let r = self.executor.execute(p)?;
        let result = encode(rpc_context, &r)?;
        Ok(result)
    }
}